package com.jinhe.tss;

import java.io.File;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.SQLExec;
import org.dom4j.Document;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit38.AbstractTransactionalJUnit38SpringContextTests;
import org.springframework.test.context.transaction.TransactionConfiguration;

import com.jinhe.tss.cms.CMSConstants;
import com.jinhe.tss.cms.entity.ArticleType;
import com.jinhe.tss.cms.service.IArticleTypeService;
import com.jinhe.tss.component.dynproperty.support.IRemotePropertyService;
import com.jinhe.tss.core.Config;
import com.jinhe.tss.core.Global;
import com.jinhe.tss.core.cachepool.extend.connection.DBHelper;
import com.jinhe.tss.core.sso.IdentityCard;
import com.jinhe.tss.core.sso.TokenUtil;
import com.jinhe.tss.core.sso.context.Context;
import com.jinhe.tss.core.util.FileHelper;
import com.jinhe.tss.core.util.URLUtil;
import com.jinhe.tss.core.util.XMLDocUtil;
import com.jinhe.tss.portal.PortalConstants;
import com.jinhe.tss.portal.entity.Decorator;
import com.jinhe.tss.portal.entity.ElementGroup;
import com.jinhe.tss.portal.entity.Layout;
import com.jinhe.tss.portal.service.IElementService;
import com.jinhe.tss.um.UMConstants;
import com.jinhe.tss.um.entity.Group;
import com.jinhe.tss.um.helper.dto.OperatorDTO;
import com.jinhe.tss.um.permission.PermissionService;
import com.jinhe.tss.um.permission.ResourcePermission;
import com.jinhe.tss.um.service.IGroupService;
import com.jinhe.tss.um.service.ILoginService;
import com.jinhe.tss.um.service.IResourceRegisterService;

/**
 * 初始化数据库。
 * 
 * 需使用 src/main/resources目录下的配置文件，比如persistence.xml, application.properties等。
 * 需把src/main/resources目录下的 persistence.xml 先重命名掉。
 * 另外，初始化时需要把applicationContext.xml的<property name="generateDdl" value="true" /> 设置为true
 */
@ContextConfiguration(
        locations={
          "classpath:spring/core-applicationContext.xml",
          "classpath:spring/component-applicationContext.xml",  
          "classpath:spring/um-applicationContext.xml",
          "classpath:spring/cms-applicationContext.xml",
          "classpath:spring/portal-applicationContext.xml",
          "classpath:spring/applicationContext.xml",
        } 
      )
@TransactionConfiguration(defaultRollback = false) // 不自动回滚，否则后续的test中没有初始化的数据
public class InitDatabase extends AbstractTransactionalJUnit38SpringContextTests { 
 
    Logger log = Logger.getLogger(this.getClass());    
    
    @Autowired private IResourceRegisterService resourceRegisterService;
    @Autowired private ResourcePermission resourcePermission;
    @Autowired private IRemotePropertyService propertyService;
    @Autowired private IGroupService groupService;
    @Autowired private ILoginService loginSerivce;
    @Autowired private PermissionService permissionService;
    
    @Autowired private IArticleTypeService articleTypeService;
    @Autowired private IElementService elementService;
    
    protected void setUp() throws Exception {
        super.setUp();
        Global.setContext(super.applicationContext);
    }
    
    public void testInitDatabase() {
        log.info("create tss databse schema success.");
 
        //------------------------------- 利用ANT執行sql目錄下的腳本 --------------------
        // 设置数据库参数
        SQLExec sqlExec = new SQLExec();
        sqlExec.setDriver(Config.getAttribute(DBHelper.DB_CONNECTION_DRIVER_CLASS));
        sqlExec.setUrl(Config.getAttribute(DBHelper.DB_CONNECTION_URL));
        sqlExec.setUserid(Config.getAttribute(DBHelper.DB_CONNECTION_USERNAME));
        sqlExec.setPassword(Config.getAttribute(DBHelper.DB_CONNECTION_PASSWORD));
        
        //有出错的语句该如何处理
        SQLExec.OnError onError = new SQLExec.OnError();
        onError.setValue("abort");  //abort/conitue/stop
        sqlExec.setOnerror(onError);
        
        // 设置是否输出
        sqlExec.setPrint(true);
        sqlExec.setProject(new Project());
        
        //输出到文件 sql.out 中；不设置该属性，默认输出到控制台
        //sqlExec.setOutput(new File("src/sql.out")); 
        
        String path = URLUtil.getResourceFileUrl("com/jinhe/tss").getPath();
        String sqlpath = path.substring(1, path.indexOf("jinhe-tss") + 9) + "/tss-webapp/sql";
        
        List<File> sqlFiles = FileHelper.listFilesByTypeDeeply(".sql", new File(sqlpath));
        for(File sqlFile : sqlFiles) {
            if("roleusermapping-init.sql".equals(sqlFile.getName())) {
                continue;
            }
            
            log.info("開始执行SQL脚本：" + sqlFile);  
            sqlExec.setSrc(sqlFile); // 要执行的脚本
            sqlExec.execute();
        }
 
        //-------------------------------初始化系統的必要数据 --------------------
        // 初始化虚拟登录用户信息
        OperatorDTO loginUser = new OperatorDTO(UMConstants.ADMIN_USER_ID, UMConstants.ADMIN_USER_NAME);
        String token = TokenUtil.createToken("1234567890", UMConstants.ADMIN_USER_ID); 
        IdentityCard card = new IdentityCard(token, loginUser);
        Context.initIdentityInfo(card);
        
        // 获取登陆用户的权限（拥有的角色）并保存到用户权限（拥有的角色）对应表
        List<Object[]> userRoles = loginSerivce.getUserRolesAfterLogin(UMConstants.ADMIN_USER_ID);
        permissionService.saveUserRolesAfterLogin(userRoles, UMConstants.ADMIN_USER_ID);
        
        initUM();
        initCMS();
        initPortal();
        
        log.info("init tss databse base data over.");
    }
 
    /**
     * 初始化UM、CMS、Portal相关应用、资源类型、权限选型信息
     */
    private void initUM() {
        /* 初始化应用系统、资源、权限项 */
        String path = URLUtil.getResourceFileUrl("com/jinhe/tss").getPath();
        String rootpath = path.substring(1, path.indexOf("jinhe-tss") + 9);
        String sqlpath = rootpath + "/tss-webapp/sql";
        Document doc = XMLDocUtil.createDocByAbsolutePath(sqlpath + "/tss-application-config.xml");
        resourceRegisterService.setInitial(true);
        resourceRegisterService.applicationRegisterByXML(doc, UMConstants.PLATFORM_SYSTEM_APP);
        resourceRegisterService.setInitial(false);
        
        // 补全SQL初始化出来的系统级用户组
        Long[] groupIds = new Long[] {-2L, -3L, -4L, -7L, -8L, -9L};
        for(Long groupId : groupIds) {
            Group group = groupService.getGroupById(groupId);
            if ( Group.MAIN_GROUP_TYPE.equals( group.getGroupType() ) ) {
                resourcePermission.addResource(group.getId(), UMConstants.MAINGROUP_RESOURCE_TYPE_ID);
            }
            if ( Group.ASSISTANT_GROUP_TYPE.equals( group.getGroupType() )) {
                resourcePermission.addResource(group.getId(), UMConstants.ASSISTANTGROUP_RESOURCE_TYPE_ID);
            }
            if ( Group.OTHER_GROUP_TYPE.equals( group.getGroupType() ) ) {
                resourcePermission.addResource(group.getId(), UMConstants.OTHERAPPGROUP_RESOURCE_TYPE_ID);
            }
        }
        
        /** 注册动态属性实体（包括用户、各种用户组、站点栏目、文章等） */
        String umDynpath = rootpath + "/tss-um/src/main/resources/template/dyninit/";
        List<String> files = FileHelper.listFilesByType(".xml", new File(umDynpath));
        for( String fileName : files ){
            Document dynDoc = XMLDocUtil.createDocByAbsolutePath(umDynpath + "/" + fileName);
            propertyService.importDynableEntity(dynDoc.asXML());
        }
        
        String cmsDynpath = rootpath + "/tss-cms/src/main/resources/template/dyninit/";
        files = FileHelper.listFilesByType(".xml", new File(cmsDynpath));
        for( String fileName : files ){
            if (!"ArticleProperties.xml".equals(fileName)) {
                Document dynDoc = XMLDocUtil.createDocByAbsolutePath(cmsDynpath + "/" + fileName);
                propertyService.importDynableEntity(dynDoc.asXML());
            }
        }
    }
    
    /** 初始化一个普通文章类型 */
    protected void initCMS() {
        ArticleType articleTypeGroup = new ArticleType();
        articleTypeGroup.setName("基本类型组");
        articleTypeGroup.setParentId(CMSConstants.HEAD_NODE_ID);
        articleTypeGroup.setIsGroup(CMSConstants.TRUE);
        articleTypeGroup = articleTypeService.createArticleType(articleTypeGroup);
        
        ArticleType defaultArticleType = new ArticleType();
        defaultArticleType.setName("默认文章类型");
        defaultArticleType.setParentId(articleTypeGroup.getId());
        defaultArticleType.setIsGroup(CMSConstants.FALSE);
        defaultArticleType = articleTypeService.createArticleType(defaultArticleType);
        
        // 将文章的模板导入到动态属性实体中
        Document doc = XMLDocUtil.createDoc(CMSConstants.TEMPLATE_ARTICLE_PROPERTY);
        Element root = doc.getRootElement();
        root.addAttribute("name", defaultArticleType.getName());
        root.addAttribute("code", defaultArticleType.getEntityCode());
        propertyService.importDynableEntity(doc.asXML());
    }
 
    
    /** 初始化默认的修饰器，布局器 */
    private void initPortal() {
        ElementGroup defaultLayoutGroup = new ElementGroup();
        defaultLayoutGroup.setName("默认布局器组");
        defaultLayoutGroup.setType(ElementGroup.LAYOUT_TYPE);
        defaultLayoutGroup.setParentId(PortalConstants.ROOT_ID);   
        defaultLayoutGroup = elementService.saveGroup(defaultLayoutGroup);
        
        Layout defaultLayout = new Layout();
        defaultLayout.setIsDefault(PortalConstants.TRUE);
        defaultLayout.setGroupId(defaultLayoutGroup.getId());   
        Document document = XMLDocUtil.createDoc("template/initialize/defaultLayout.xml");
        Element propertyElement = document.getRootElement().element("property");
        String layoutName = propertyElement.elementText("name");
        defaultLayout.setName(layoutName);
        defaultLayout.setPortNumber(new Integer(propertyElement.elementText("portNumber")));
        defaultLayout.setDefinition(document.asXML());
        elementService.saveElement(defaultLayout);
        
        ElementGroup defaultDecoratorGroup = new ElementGroup();
        defaultDecoratorGroup.setName("默认修饰器组");
        defaultDecoratorGroup.setType(ElementGroup.DECORATOR_TYPE);
        defaultDecoratorGroup.setParentId(PortalConstants.ROOT_ID);  
        defaultDecoratorGroup = elementService.saveGroup(defaultDecoratorGroup);
        
        Decorator defaultDecorator = new Decorator();
        defaultDecorator.setIsDefault(PortalConstants.TRUE);
        defaultDecorator.setGroupId(defaultDecoratorGroup.getId());
        
        document = XMLDocUtil.createDoc("template/initialize/defaultDecorator.xml");
        propertyElement = document.getRootElement().element("property");
        String decoratorName = propertyElement.elementText("name");
        defaultDecorator.setName(decoratorName);
        defaultDecorator.setDefinition(document.asXML());
        elementService.saveElement(defaultDecorator);
    }
}
